#!/bin/bash
CUR_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )"
GH_PROXY=${URL_githubProxy:-https://ghproxy.com/}
CALICO_MANIFESTS=(
  ${GH_PROXY}${URL_calico_manifest_0:-"https://raw.githubusercontent.com/projectcalico/calico/v\${TARGET_VERSION}/manifests/calico.yaml"}
)
CALICO_CHART=${GH_PROXY}${URL_calico_chart:-"https://github.com/projectcalico/calico/releases/download/v\${TARGET_VERSION}/tigera-operator-v\${TARGET_VERSION}.tgz"}
#二进制包下载路径
ARCH=$(uname -m | sed 's/x86_64/amd64/;s/aarch64/arm64/')

DOWNLOAD_DIR=$CUR_DIR/package
DEFAULT_VERSION=${LATEST_VERSION:-3.26.1}

# 检查是否有curl和wget
HAS_CURL="$(command -v curl >/dev/null 2>&1 && echo true || echo false)"
HAS_WGET="$(command -v wget >/dev/null 2>&1 && echo true || echo false)"
bash_xc="bash -xc"
if ! $HAS_CURL && ! $HAS_WGET; then
  echo "Either curl or wget is required"
  exit 1
fi

##include scripts##
##include end##


#usage: download_url <url> [target] 
download_url() {
  local target
  local url=$1
  local remote_file=""
  
  if [ $# -eq 2 ]; then
    target=$2
  elif [ $# -eq 1 ]; then 
    target=${1##*/}
  else
    echo "cmd err, usage: download_url <url> [target]"
    return 1
  fi
  if [ ! -f "$target" ] || ${FORCE} ; then
    if $HAS_CURL; then
      $bash_xc "curl -fsSL $url -o $target"
      if [ $? -ne 0 ]; then
        echo "curl or wget failed"
        return 3
      fi
    elif $HAS_WGET; then
      $bash_xc "wget -q $url -O $target"
      if [ $? -ne 0 ]; then
        echo "curl or wget failed"
        return 3
      fi
    fi
    echo "get $(basename $target) successfully"
    return 0
  else
    echo "do not get $(basename $url): file exist or force=${FORCE} "
    return 0
  fi
  return 0
}

download_url_until_succeed() {
  local target
  local url=$1
  
  if [ $# -eq 2 ]; then
    target=$2
  elif [ $# -eq 1 ]; then 
    target=${1##*/}
  else
    echo "cmd err, usage: download_url <url> [target]"
    return 1
  fi
  echo "download $url $target"
  
  while ! download_url $url $target; do
    sleep 5
  done
}


#set -x
# Define functions to check version and install Kubernetes components

# check if the current version is less than the target version.
# 检查当前版本是否小于目标版本。
check_version_lt() {
    test "$(echo "$@" | tr " " "\n" | sort -rV | head -n 1)" != "$1"
}

# check if the current version is greater than or equal to the target version.
# 检查当前版本是否大于或等于目标版本。
check_version_ge() {
    test "$(echo "$@" | tr " " "\n" | sort -rV | head -n 1)" == "$1"
}

# get the latest version of Kubernetes components.
# 获取 Kubernetes 组件的最新版本。
get_latest_version() {
    local regex='[0-9]+\.([0-9]+)\.([0-9]+)'
    if [ "$PACKAGE_MANAGER" == "apt-get" ]; then
        echo $(apt-cache madison kubeadm | head -1 | grep -Eo "$regex")
    elif [ "$PACKAGE_MANAGER" == "yum" ]; then
        echo $(yum list kubeadm --showduplicates | grep -Eo "$regex" | sort -rV | head -1)
    fi
}

get_default_version() {
    #if $ONLINE; then
    #    echo $(get_latest_version)
    #else
    echo "$DEFAULT_VERSION"
    #fi
}

# Check if Kubernetes components are installed and if they need to be upgraded
calico_needs_installation() {
    if [ -x "$(command -v /opt/cni/bin/calico)" ]; then
        CURRENT_VERSION=$(/opt/cni/bin/calico -v)
        #echo "Current version: $current_version, target version: $TARGET_VERSION"
        if [ -z "$TARGET_VERSION" ] && [ "$FORCE" = "false" ]; then
            echo "Current version is $CURRENT_VERSION, use '--force=true' or '--verion=<version> to install as desired"
            return 1
        elif check_version_ge "$CURRENT_VERSION" "$TARGET_VERSION" && [ "$FORCE" != "true" ]; then
            echo "Current version ($CURRENT_VERSION) >= target version($TARGET_VERSION), and force=$FORCE; no need to install"
            return 1
        fi
    fi
    return 0
}

# deletes the old version of Kubernetes components.
# 删除旧版本的 Kubernetes 组件。
delete_old_version() {
    if [ -z "$TARGET_VERSION" ]; then
        if [ -x "$(command -v /opt/cni/bin/calico)"  ]; then
            TARGET_VERSION=$(/opt/cni/bin/calico -v)
            TARGET_VERSION=${TARGET_VERSION#*v}
        else
            echo "calico are not installed"
            #return
        fi
    fi
    echo "Delete version $CURRENT_VERSION ..."

	yamls=$(ls $CUR_DIR/manifest/{*.yaml,*.yml} 2>/dev/null)
	for i in $yamls; do
		bash -xc "kubectl delete -f $i > /dev/null 2>&1"
	done

	CALICO_CHART=$(eval echo ${CALICO_CHART})
	if [ -f $CUR_DIR/chart/${CALICO_CHART##*/} ]; then
		bash -xc "helm uninstall calico --namespace tigera-operator > /dev/null 2>&1"
	fi
	rm -rf /opt/cni/bin/calico

}

waiting_for_etcd() {
  echo -en "waiting for etcd to be ready "
  while true ; do
    if ps -eo cmd  | grep -o "^etcd " ; then
	  echo -en " ok\n"
      break
    else
	  echo -en "."
      sleep 3
    fi
  done
}

waiting_for_keepalived() {
  echo -en "waiting for keepalived to be ready"
  while true ; do
    if ps -eo cmd  | grep -o "^/usr/sbin/keepalived " ; then
	  echo -en " ok\n"
      break
    else
	  echo -en "."
      sleep 3
    fi
  done
}

waiting_for_kubernetes() {
  kubeApiServer=$(kubectl cluster-info | grep "Kubernetes control plane" | grep -oE "http.*://.*:[0-9]*")
  if [ -z "$kubeApiServer" ]; then
      echo "kubernetes not installed, exit\n"
      exit
  fi
  echo -en "waiting for kubernetes to be ready  "
  while true; do
    if [ "$(curl -k --silent --max-time 3 ${kubeApiServer}/healthz)" == "ok" ] ; then
	  echo -en " ok\n"
      break
    else
	  echo -en "."
      sleep 3
    fi
  done
}
install_calico() {
    download_pkg
    set -x
    waiting_for_etcd
	waiting_for_kubernetes
	if [ $DEPLOY_MODE == "manifest" ]; then
	    yamls=$(ls $CUR_DIR/manifest/{*.yaml,*.yml} 2>/dev/null)
		for i in $yamls; do
		    kubectl apply -f $i
		done
	elif [ $DEPLOY_MODE == "manifest" ]; then
	    if [ -f $CUR_DIR/chart/${CALICO_CHART##*/} ]; then
		    kubectl create namespace tigera-operator
		    helm install calico $CUR_DIR/chart/${CALICO_CHART##*/} --namespace tigera-operator  -f $CUR_DIR/chart/values.yaml
		fi
	fi
    set +x
}
download_pkg() {
    bash -xc "mkdir -p $CUR_DIR/{manifest,chart}"
    CALICO_MANIFEST=$(eval echo ${CALICO_MANIFEST})
    CALICO_CHART=$(eval echo ${CALICO_CHART})

	for i in ${CALICO_MANIFESTS[@]}; do
		local yaml=$(eval echo ${i})
		local ext=${yaml##*.}
		local filename=$(basename ${yaml##*/} .$ext)-${TARGET_VERSION}.yaml
		if [ ! -f $CUR_DIR/manifest/$filename ]; then
			download_url_until_succeed ${yaml} $CUR_DIR/manifest/$filename
		fi
	done

    #cp -rf $CUR_DIR/manifest/calico-${TARGET_VERSION}.yaml $DOWNLOAD_DIR/manifest/
	
    if [ ! -f $CUR_DIR/chart/${CALICO_CHART##*/} ]; then
        download_url_until_succeed ${CALICO_CHART} $CUR_DIR/chart/${CALICO_CHART##*/}
    fi
	#cp -rf $CUR_DIR/chart/${CALICO_CHART##*/} $DOWNLOAD_DIR/chart/
	if [ ! -f $CUR_DIR/chart/values.yaml ] ; then
	    tar -xzf $CUR_DIR/chart/${CALICO_CHART##*/} --strip-components=1 -C $CUR_DIR/chart/ tigera-operator/values.yaml
	fi
	#cp -rf $CUR_DIR/chart/values.yaml $DOWNLOAD_DIR/chart/
}


clean_download() {
    rm -rf $CUR_DIR/chart
    rm -rf $CUR_DIR/manifest
}
function print_usage() {
    echo "Usage: $0 [--force|-f] [--version=<version>] [--rm|--remove] [--clean|-c] [--downloadonly|-d][--deployMode=<manifest|chart>]"
    echo "Options:"
    echo "  --force|-f: force installation, default force=false"
    echo "  --version=<version>: specify the version to be installed, default is latest(online) or 20.10.24(apt/yum)"
    echo "  --rm|--remove: uninstall Kubernetes"
    echo "  --clean|-c: remove downloaded files"
    echo "  --downloadonly|-d: only download kubernetes package, do not install"
	echo "  --deployMode=[manifest|chart]: manifest: kubectl apply -f x.yaml, chart: helm install"
    echo "  example1, download 3.26.1 "
    echo "          ./install.sh --version=3.26.1 --force --downloadonly"
    echo "  example2, install 3.26.1" 
    echo "         ./install.sh --version=3.26.1"
    echo "  example3, install 3.26.1 using online method(by apt or yum), and force installation:" 
    echo "         ./install.sh --version=3.26.1  -fo"
}

#
#=====================main func ==============================
if [[ $EUID -ne 0 ]]; then
    echo "This script must be run as root"
    exit 1
fi

#清除旧版本的影响，保证command -v命令得到正确的结果
hash -r

ARGS=$#

# Parse command line arguments
while [[ $# -gt 0 ]]
do
    key="$1"
    case $key in
    --clean|-c)
        if [[ $ARGS -eq 1 ]]; then
            clean_download
            exit 0
        fi
        AUTOCLEAN=true
        shift
        ;;
    --downloadonly|-d)
        DOWNLOAD_ONLY=true
        shift
        ;;
    --force|-f)
        FORCE=true
        shift
        ;;
    --version)
        shift
        TARGET_VERSION="${key}"
        shift
        ;;
    --version=*)
        TARGET_VERSION="${key#*=}"
        shift
        ;;
	--deployMode)
        shift
        DEPLOY_MODE="${key}"
        shift
        ;;
    --deployMode=*)
        DEPLOY_MODE="${key#*=}"
        shift
        ;; 	
    --help)
        print_usage
        exit 1
        ;;
    --rm|--remove)
        echo "Kubernetes components uninstall..."
        delete_old_version
        exit 1
        ;;
    -[^-]*)
        for ((i=1; i<${#key}; i++)); do
          case "${key:$i:1}" in
            f) FORCE=true ;;
            c) AUTOCLEAN=true ;;
            d) DOWNLOAD_ONLY=true ;;
            *) print_usage; exit 1 ;;
          esac
        done
        shift    
        ;;
    *)    # unknown option
        print_usage
        exit 1
        ;;
    esac
done

FORCE=${FORCE:-false}
DOWNLOAD_ONLY=${DOWNLOAD_ONLY:-false}
AUTOCLEAN=${AUTOCLEAN:-false}

#设置软件安装源，从而获得最新版本
TARGET_VERSION=${TARGET_VERSION:-$(get_default_version)}
DEPLOY_MODE=${DEPLOY_MODE:-manifest}

echo "--version=$TARGET_VERSION --force=$FORCE --downloadonly=$DOWNLOAD_ONLY --clean=$AUTOCLEAN --deployMode=$DEPLOY_MODE"

if $DOWNLOAD_ONLY ; then
    download_pkg
    exit 0
fi
# Main script
#if calico_needs_installation; then
    [ -n "$CURRENT_VERSION" ] && delete_old_version

    echo "Install version $TARGET_VERSION ..."
    install_calico
    $AUTOCLEAN && clean_download
#fi

